package edu.ilstu.mind.ise.ccp.module;

import edu.ilstu.mind.ise.ccp.logger.Logger;
import edu.ilstu.mind.ise.ccp.message.Message;
import edu.ilstu.mind.ise.ccp.message.MessageFactory;
import edu.ilstu.mind.ise.ccp.message.MessageSender;
import edu.ilstu.mind.ise.ccp.message.MutableMessage;

/**
 * Abstract implementation of the Module Interface for convenience purposes. The
 * message sender/factory logic is hidden and a protected sendMessage function
 * is provided to the implementing class instead. Throwables are also caught and
 * logged.
 * 
 * @author Eric Thill
 * 
 */

public abstract class AbstractModule implements Module {

	private MessageFactory messageFactory;
	private MessageSender sender;
	private Logger logger;

	@Override
	public final void setMessageFactory(MessageFactory messageFactory) {
		this.messageFactory = messageFactory;
	}

	@Override
	public final void setMessageSender(MessageSender sender) {
		this.sender = sender;
	}

	@Override
	public final void setLogger(Logger logger) {
		this.logger = logger;
	}

	protected final Logger getLogger() {
		return logger;
	}

	/**
	 * Used to create the empty message to send over the CCP.
	 * 
	 * @param to
	 *            The module to send the message to
	 * @param subject
	 *            The subject of the message
	 * @param numFields
	 *            The number of fields that will be populated
	 * 
	 * @return The created message
	 */
	protected final MutableMessage createMessage(String to, int numFields) {
		return messageFactory.createMessage(to, numFields);
	}

	/**
	 * Used to send a message to another module
	 * 
	 * @param message
	 *            The message to send
	 */
	protected final void sendMessage(MutableMessage message) {
		// log message is sending
		if (logger.isTraceEnabled()) {
			logger.trace("Sending Message - " + message.toString() + "");
		}
		// finalize message so other modules can't modify the contents
		message.finalizeMessage();
		// send the message
		sender.sendMessage(message);
	}

	@Override
	public final void processMessage(Message message) {
		try {
			// log message was received
			if (logger.isTraceEnabled()) {
				logger.trace("Received Message - " + message.toString());
			}
			// call onMessage for module to process the message
			boolean success = onMessage(message);
			// warn if message was unrecognized
			if(!success) {
				logger.warn("Unknown message received: " + message.toString());
			}
		} catch (Throwable t) {
			// log unhandled exceptions so we don't crash the thread
			logger.error("Unhandled Exception", t);
		}
	}

	/**
	 * Called when a message is received and should be processed by the module
	 * 
	 * @param message
	 *            The message
	 * @return true if the message was recognized, false if it was unrecognized
	 */
	protected abstract boolean onMessage(Message message);
}
